﻿using System;
using System.Collections.Generic;
using System.Security.Cryptography;

namespace Noria.Web.MyMSDN.Checksum
{
    internal sealed class AsyncED2K : ED2KManaged
    {
        public new void HashCore(byte[] rgb, int ibStart, int cbSize)
        {
            base.HashCore(rgb, ibStart, cbSize);
        }

        public new byte[] HashFinal()
        {
            return base.HashFinal();
        }
    }

    internal abstract class ED2K : HashAlgorithm
    {
        protected ED2K()
        {
            // ED2K hash length are 128 bits long
            HashSizeValue = 128;
        }
    }

    internal class ED2KManaged : ED2K
    {
        private const int PARTSIZE = 9728000;
        private List<Byte> hashList;
        private AsyncMD4 md4;
        private int ed2kPos;

        protected ED2KManaged()
        {
            hashList = new List<Byte>();
            md4 = new AsyncMD4();
        }

        protected override void HashCore(byte[] array, int ibStart, int cbSize)
        {
            //if (cbSize > PARTSIZE)
            //    throw new Exception("cbSize must be less than " + PARTSIZE);

            //md4.Initialize();
            //hashList.AddRange(md4.ComputeHash(array, ibStart, cbSize));
            int currentPos = ibStart;
            while (cbSize > 0)
            {
                if (ed2kPos + cbSize >= PARTSIZE)
                {
                    var size = PARTSIZE - ed2kPos;
                    md4.HashCore(array, currentPos, size);
                    hashList.AddRange(md4.HashFinal());
                    md4.Initialize();

                    //File.WriteAllText("ed2k.txt", BitConverter.ToString(hashList.ToArray()).Replace("-", "").ToUpper());
                    //Process.Start("ed2k.txt");

                    currentPos += size;
                    cbSize -= size;
                    ed2kPos = 0;
                }
                else
                {
                    var size = cbSize;
                    md4.HashCore(array, currentPos, size);

                    currentPos += size;
                    cbSize -= size;
                    ed2kPos += size;
                }
            }
        }

        protected override byte[] HashFinal()
        {
            //md4.Initialize();
            //return md4.ComputeHash(hashList.ToArray());
            if (ed2kPos > 0)
            {
                hashList.AddRange(md4.HashFinal());
            }

            //File.WriteAllText("ed2k.txt", BitConverter.ToString(hashList.ToArray()).Replace("-", "").ToUpper());
            //Process.Start("ed2k.txt");

            md4.Initialize();
            return md4.ComputeHash(hashList.ToArray());
        }

        public override void Initialize()
        {
            hashList.Clear();
            md4.Initialize();
            ed2kPos = 0;
        }
    }
}
